package tourist

import (
	"errors"
	"github.com/go-redis/redis"
	"strconv"
	"strings"
	"time"
)

var ApiRedis apiRedis

type apiRedis uint8

type SetOne struct {
	Address string `json:"address"`
	Key     string `json:"key"`
	Value   string `json:"value"`
	Second  int64  `json:"second"`
}

type SetMany struct {
	Ordered bool   `json:"ordered"` // 是否支持事务
	Address string `json:"address"`
	Set     []struct {
		Key    string `json:"key"`
		Value  string `json:"value"`
		Second int64  `json:"second"`
	}
}

type GetOne struct {
	Address string `json:"address"`
	Key     string `json:"key"`
}

type GetMany struct {
	Address string `json:"address"`
	Key     string `json:"key"`
}

type DelOne struct {
	Address string `json:"address"`
	Key     string `json:"key"`
}

type DelMany struct {
	Address string `json:"address"`
	Key     string `json:"key"`
}

type Z struct {
	Address string                 `json:"address"`
	Key string  `json:"key"`
	Do  zType   `json:"do"`
	Z   redis.Z `json:"z"`
	Opinion map[string]interface{} `json:"opinion"`
}
type zType string

const (
	zAdd, zRange, zRevRange zType = "zAdd", "zRange", "zRevRange"
)

func getRedisClient(address string) (*redis.Client, error) {
	if Pool.Redis[address] == nil {
		opt := &redis.Options{}
		split := strings.Split(address, "@")
		if len(split) == 2 {
			opt.Password = strings.TrimPrefix(split[0], "auth:")
			addressAndDb := strings.Split(split[1], "/")
			if len(addressAndDb) == 2 {
				opt.Addr = addressAndDb[0]
				db, err := strconv.Atoi(addressAndDb[1])
				if err != nil {
					return nil, err
				}
				opt.DB = db
			} else {
				return nil, errors.New("hope address like (auth:password@127.0.0.1:3306/0)")
			}
		}
		client := redis.NewClient(opt)
		if client.Ping().Err() != nil {
			return nil, client.Ping().Err()
		}
		Pool.Redis[address] = client
	}
	return Pool.Redis[address], nil
}

func (*apiRedis) SetOne(set *SetOne) error {
	client, err := getRedisClient(set.Address)
	if err != nil {
		return err
	}
	return client.Set(set.Key, []byte(set.Value), time.Duration(set.Second)*time.Second).Err()
}

func (*apiRedis) SetMany(set *SetMany) *[]string {
	client, err := getRedisClient(set.Address)
	var errs []string
	if err != nil {
		errs = append(errs, err.Error())
		return &errs
	}
	for _, one := range set.Set {
		err = client.Set(one.Key, []byte(one.Value), time.Duration(one.Second)*time.Second).Err()
		if err != nil {
			errs = append(errs, err.Error())
			return &errs
		}
	}
	return &errs
}

func (*apiRedis) GetOne(get *GetOne) ([]byte, error) {
	client, err := getRedisClient(get.Address)
	if err != nil {
		return nil, err
	}
	return client.Get(get.Key).Bytes()
}

func (*apiRedis) GetMany(get *GetMany) (*[]interface{}, error) {
	client, err := getRedisClient(get.Address)
	if err != nil {
		return nil, err
	}
	keys := client.Keys(get.Key).Val()
	result, err := client.MGet(keys...).Result()
	return &result, err
}

func (*apiRedis) DelOne(del *DelOne) (int64, error) {
	client, err := getRedisClient(del.Address)
	if err != nil {
		return 0, err
	}
	return client.Del(del.Key).Result()
}

func (*apiRedis) DelMany(del *DelMany) (int64, error) {
	client, err := getRedisClient(del.Address)
	if err != nil {
		return 0, err
	}
	keys := client.Keys(del.Key).Val()
	return client.Del(keys...).Result()
}
